﻿using System.Collections.Generic;
using System.IO;
using System.Linq;
using LingDong.HtmlParser;
using LingDong.IndexEntities.Document;
using LingDong.IndexReader;
using NLog;

namespace LingDong.LinkAnalyser
{
    internal class PageRank : GGPageRankAlgorithm
    {
        #region Constructors

        public PageRank(Index index)
        {
            this.index = index;
        }

        #endregion


        #region Internal Methods

        internal double[] GetPageRank()
        {
            Init();
            OutDegree();
            ComputeRank();
            LogSummary(GetPageNameByID);

            return rank;
        }

        #endregion


        #region Private Methods

        private void Init()
        {
            count = index.GetTotalDocumentCount();
            inDegree = new int[count];
            outDegree = new int[count];
            rank = new double[count];

            outLinksOffset = new Dictionary<int, long>();
            outLinkTempFile = Path.GetTempFileName();
        }

        private void OutDegree()
        {
            // init url to doc id hashtable: [url, id]
            Dictionary<string, int> dicUrlToID = new Dictionary<string, int>();
            for (int i = 0; i < count; i++)
            {
                OriginalDocumentEnity oriDoc = index.GetOriginalDocument(i);
                string formatedPath = HtmlUtility.GetFormattedDomain(oriDoc.URL);
                dicUrlToID[formatedPath] = oriDoc.DocID;
            }
            
            // save doc out links to a temp file
            using (FileStream fs = new FileStream(outLinkTempFile, FileMode.Create))
            {
                for (int i = 0; i < count; i++)
                {
                    OriginalDocumentEnity oriDoc = index.GetOriginalDocument(i);
                    List<string> outLinks = new DocumentWithLinks(oriDoc.Content, oriDoc.URL).References;
                    outDegree[i] = outLinks.Count;

                    List<int> outDocIDList = new List<int>();
                    foreach (string link in outLinks)
                    {
                        if (dicUrlToID.ContainsKey(link))
                        {
                            int id = dicUrlToID[link];
                            outDocIDList.Add(id);
                            inDegree[id]++;
                        }
                    }

                    outLinksOffset[i] = fs.Position;
                    SerializeProvider.Serializer.Serialize(fs, outDocIDList);
                }
            }
        }


        private string GetPageNameByID(int id)
        {
            return index.GetParsedDocument(id).URL;
        }

        #endregion
    }
}
